/****************************************************************
 Mapa de Google Maps
 - Se definen variables globales, utilizadas desde los diversos
   scripts para el manejo del mapa
 - Se construye la clase(clase ficticias ya que no son realmente
   clases ni objetos en javascript) para el mapa
 - Se definen metodos generales y metodos que seran asignados a
   los metodos de la clase hidmapa
 *las clases llevan el prefijo "hid"
 ***************************************************************/

//mapa de Google Maps
var mapa;
//booleano que indica si se esta modificando los limites del mapa
var mapaModificado = false;

//limites del mapa
var valorMaximoLatitud = -34.397;
var valorMinimoLatitud = -34.397;
var valorMaximoLongitud = 150.644;
var valorMinimoLongitud = 150.644;

//bordes del mapa actual
var strictBounds;

//marcadores
var markersArray = [];
//arreglo de lineas(nodo inicio y nodo fin)
var lineArray = [];
//arreglo de componentes en el mapa
var componentes = [];
//arreglo de componentes eliminados
var eliminadosArray = [];
//arreglo de objetos polylines
var poly = [];
//tipos de punto de monitoreo
var tipoPuntoMonitoreo = [];

//Clase para la creacion de un mapa de google maps
function hidmapa()
{
    //metodos
    this.Inicializar = function ()
    {
        this.DefinirComponentes();
        this.Delimitar();
        this.AgregarEventosMapa();
        this.AgregarControlesMapa();
        this.MostrarMarcadores();
        this.MostrarLineas();
    };
    this.DefinirComponentes = function ()
    {
        /*Debido a que los datos son cargados de la base de datos, estos
          son puestos previamente en entradas (inputs html) a partir de
          los cuales se obtienen los mismos*/

        /* Se debe obtener la informacion de los componentes (nombres, latitudes, etc) */
        var latcomponentes = ExtraerLista("idlatitudes",",");
        var lngcomponentes = ExtraerLista("idlongitudes",",");
        var nombcomponentes = ExtraerLista("idnombres",",");
        var tipospuntosmonitoreo = ExtraerLista("idtiposptomon",",");

        /* se debe obtener los tipos(indicando si son para objetos unicos o lineas)*/
        var tipos = ExtraerLista("idtipos",",");
        var tiposuni = ExtraerLista("idtiposuni",",");

        /* se debe obtener los ids*/
        var ids = ExtraerLista("idids",",");
        var aristas = ExtraerLista("idaristas",";");

        /* ruta donde se ubican las imagenes de los componentes*/
        var rutaBase = this.ObtenerRutaComponentes();

        //Con la informacion se crean los objetos nodos y aristas
        var aristasArray = this.CrearComponentesNodo(ids,tipos,tiposuni,latcomponentes,lngcomponentes, aristas, rutaBase, nombcomponentes, tipospuntosmonitoreo);
        this.CrearComponentesArista(aristasArray);
    };
    this.Delimitar = function()
    {
        /* Necesitamos obtener los limites del mapa */
        var latitudminima = ExtraerValor("latiminima");
        var latitudmaxima = ExtraerValor("latimaxima");
        var longitudminima = ExtraerValor("longminima");
        var longitudmaxima = ExtraerValor("longmaxima");

        // Se debe asignar los limites obtenidos del mapa en variables globales
        this.AlmacenarLimites(longitudmaxima, latitudmaxima, longitudminima, latitudminima);

        // Se debe encontrar el centro del mapa para ubicarlo y con ella crear el mapa propiamente dicho
        var latlng = this.ObtenerPosicionCentralMapa(longitudmaxima, latitudmaxima, longitudminima, latitudminima);
        this.DefinirMapa(latlng);
    };
    this.AgregarEventosMapa = function()
    {
        //Debemos de agregar funcionalidades al mapa cuando ocurran diversos eventos
        //Se debe controlar que al arrastrar el mapa no supere los bordes
        google.maps.event.addListener(mapa, 'dragend', this.ControlarBordes);
        //se debe cntrolar que el acercamiento al mapa no supere los limites del mapa, es decir que no se pueda alejar
        //la imagen y nos permita ver parte del mapa fuera de los bordes definidos
        google.maps.event.addListener(mapa, 'zoom_changed', ControlarZoom);
        //Se debe permitir agregar los marcadores dentro del mapa
        google.maps.event.addListener(mapa, 'click', function(event) {
            //se debe verificar si fue seleccionado un componente de la lista de componentes
            if(document.getElementById("marcador").value != "")
            {
                //se agrega una ventana de dialogo para ingresar los datos del componente
                AgregarNombre(event.latLng);
            }
        });
    };
    this.AgregarControlesMapa = function()
    {
        /* Se debe agregar dentro del mapa "div" para agregar botones dentro del mapa */
        var homeControlDiv = document.createElement('DIV');
        var controlesmapa = new hidcontrolmapa(homeControlDiv);
        controlesmapa.InicializarControles();
        controlesmapa.controlDiv.index = 1;

        //se debe indicar la posicion dentro del mapa donde estaran los controladores
        mapa.controls[google.maps.ControlPosition.TOP_LEFT].push(controlesmapa.controlDiv);
    };
    this.MostrarMarcadores = MostrarMarcadores;
    this.MostrarLineas =  MostrarLineas;
    this.ControlarBordes = ControlarBordes;
    this.AgregarEventoLinea = AgregarEventoLinea;
    this.EliminarLinea = EliminarLinea;


    this.ObtenerRutaComponentes = function ()
    {
        var rutaBase = '../../../../public/images/Componentes/';
        return rutaBase;
    }
    this.CrearComponentesNodo = function (ids, tipos, tiposuni, latcomponentes, lngcomponentes,arist, rutaBase, nombcomponentes, tipospuntosmonitoreo)
    {
        var contador = 0;
        var aristasArray = [];

        /* se debe de crear objetos de tipo componentes con los datos que se cargan */
        for (var i = 0; i < latcomponentes.length - 1; i++)
        {
            if(this.esNodo(tiposuni[i]))
            {
                //creamos y agregamos los componentes a la lista de componentes nodos
                var componente = this.CrearComponenteNodo(ids[i], tipos[i], tiposuni[i], latcomponentes[i], lngcomponentes[i], nombcomponentes[i], tipospuntosmonitoreo[i]);
                this.CrearMarcador(componente.latitud, componente.longitud, 'Componente', rutaBase, componente);
            }
            else
            {
                //definimos los componente de mas de un elementos
                var aristadiv = [];
                aristadiv = arist[contador].split(",");

                //creamos y agregamos los componentes a la lista de componentes arista
                var arista = this.CrearComponenteArista(aristadiv, tipos[i],nombcomponentes[i], tipospuntosmonitoreo[i]);
                aristasArray.push(arista);
                contador++;
            }
        }

        return aristasArray;
    }
    this.CrearComponenteNodo = function (ids, tipos, tiposuni, latcomponentes, lngcomponentes, nombcomponentes,tipopuntosmonitoreo)
    {
        //creamos un objeto componente (nodo)
        var componente = new hidcomponente(ids, tipos, tiposuni, latcomponentes, lngcomponentes, nombcomponentes, tipopuntosmonitoreo);
        //agregamos los componentes a la lista de componentes
        componentes.push(componente);
        return componente;
    }
    this.CrearComponentesArista = function (aristasArray)
    {
        //creamos un objeto componente temporal solo para utilizar sus metodos
        var cmp = new hidcomponente(1,1,1,1);

        for (var j = 0; j < aristasArray.length; j++)
        {
            //encontramos los nodos que pertenecen a una arista
            var posicion1 = cmp.hidcomp_findById(componentes,aristasArray[j].idnodoinicio);
            var posicion2 = cmp.hidcomp_findById(componentes,aristasArray[j].idnodofin);
            var nodoinicio = componentes[posicion1];
            var nodofin = componentes[posicion2];

            //almacenamos sus datos dentro de una lista y agregamos dicha lista al
            //arreglo de aristas
            var inifin = [];

            inifin.push(nodoinicio.latitud);
            inifin.push(nodoinicio.longitud);
            inifin.push(nodofin.latitud);
            inifin.push(nodofin.longitud);
            inifin.push(aristasArray[j].tipo);
            inifin.push(aristasArray[j].ide);

            inifin.push(nodoinicio.ide);
            inifin.push(nodofin.ide);
            inifin.push(aristasArray[j].nombrearista);
            inifin.push(aristasArray[j].tipoptomon);

            lineArray.push(inifin);
        }
    }
    this.CrearComponenteArista = function (aristadiv, tipo, nombrearista, tipospuntosmonitoreo)
    {
        var aristas = {"idnodoorigen":0, "idnodofin":1, "idarista":2};
        var arista = new hidarista(aristadiv[aristas.idarista], tipo, aristadiv[aristas.idnodoorigen],aristadiv[aristas.idnodofin], nombrearista, tipospuntosmonitoreo);
        return arista;
    }
    this.CrearMarcador = function (latitud, longitud, nombre, rutaBase, componente)
    {
        //se debe agregar los eventos para cada marcador correspondiente a cada evento
        var posicion = new google.maps.LatLng(latitud,longitud);
        var nuevoMarcador = new hidmarcador(posicion, nombre, rutaBase, componente.tipoptomon);
        nuevoMarcador.AgregarEventosMarcador(componente);
    }
    this.esNodo = function (tipo)
    {
        //verificamos si el tipo componente obtenido es un nodo, es decir si en tipo unico es true
        if(tipo == "true")
            return true;
        else
            return false;
    }
    this.AlmacenarLimites = function (lonmax, latmax, lonmin, latmin)
    {
        valorMaximoLongitud = lonmax;
        valorMaximoLatitud = latmax;
        valorMinimoLongitud = lonmin;
        valorMinimoLatitud = latmin;
    }
    this.ObtenerPosicionCentralMapa = function (lonmax, latmax, lonmin, latmin)
    {
        /* Se debe encontrar el centro del mapa para ubicarlo  */
        var longitudpromedio = (parseFloat(lonmax) + parseFloat(lonmin))/2;
        var latitudpromedio = (parseFloat(latmax) + parseFloat(latmin))/2;

        //Se debe hacer el redondeo correspondiente
        longitudpromedio = longitudpromedio*Math.pow(10,14);
        latitudpromedio = latitudpromedio*Math.pow(10,14);

        longitudpromedio = Math.round(longitudpromedio);
        latitudpromedio = Math.round(latitudpromedio);

        longitudpromedio = longitudpromedio/Math.pow(10,14);
        latitudpromedio = latitudpromedio/Math.pow(10,14);

        //variable donde se almacenara el valor correspondiente al centro del mapa
        var latlng;

        /* Se debe verificar que los limites posean un valor */
        if(lonmax != 0 && latmax != 0 && lonmin != 0 && latmin != 0)
        {
            latlng = new google.maps.LatLng(latitudpromedio, longitudpromedio);
        }
        else
        {
            //valor por defecto (deberian ser las coordenadas de Arequipa)
            latlng = new google.maps.LatLng(-34.397, 150.644);
        }
        return latlng;
    }
    this.DefinirMapa = function (latlng)
    {
        var myOptions = {
            zoom: 8,
            center: latlng,
            disableDefaultUI: true,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            disableDoubleClickZoom: true
        };

        //creamos el mapa
        mapa = new google.maps.Map(document.getElementById("map_canvas"),myOptions);

        //asignamos los bordes del mapa a una variable global
        strictBounds = mapa.getBounds();
    }
}

function ControlarBordes()
{
    //se obtiene los valores de los bordes del nuevo mapa
    var nuevosBordes = mapa.getBounds();
    var valorMaximoLongitudParcial = nuevosBordes.getNorthEast().lng();
    var valorMaximoLatitudParcial = nuevosBordes.getNorthEast().lat();
    var valorMinimoLongitudParcial = nuevosBordes.getSouthWest().lng();
    var valorMinimoLatitudParcial = nuevosBordes.getSouthWest().lat();

    //Verificar que el mapa no este en estado de modificacion
    if(mapaModificado != true)
    {
        //se debe de verificar que los bordes no sean los inicializados por defecto
        if(valorMaximoLatitud != 0 && valorMinimoLatitud != 0 && valorMaximoLongitud != 0 && valorMinimoLongitud != 0)
        {
            /*  Comprobamos que los limites de la posicion actual del mapa
             *  no superen los limites establecidos
             * */

            if(valorMaximoLongitudParcial > valorMaximoLongitud)
            {
                var dif = (valorMaximoLongitudParcial - valorMaximoLongitud);
                valorMaximoLongitudParcial = valorMaximoLongitudParcial - dif;
                valorMinimoLongitudParcial = valorMinimoLongitudParcial - dif;
            }

            if(valorMinimoLongitudParcial < valorMinimoLongitud)
            {
                var dif = (valorMinimoLongitud - valorMinimoLongitudParcial);
                valorMinimoLongitudParcial = valorMinimoLongitudParcial + dif;
                valorMaximoLongitudParcial = valorMaximoLongitudParcial + dif;
            }

            if(valorMaximoLatitudParcial > valorMaximoLatitud)
            {
                var dif = (valorMaximoLatitudParcial - valorMaximoLatitud);
                valorMaximoLatitudParcial = valorMaximoLatitudParcial - dif;
                valorMinimoLatitudParcial = valorMinimoLatitudParcial - dif;
            }

            if(valorMinimoLatitudParcial < valorMinimoLatitud)
            {
                var dif = (valorMinimoLatitud - valorMinimoLatitudParcial);
                valorMinimoLatitudParcial = valorMinimoLatitudParcial + dif;
                valorMaximoLatitudParcial = valorMaximoLatitudParcial + dif;
            }


            //se debe calcular la nueva posicion del centro del mapa
            var lonpro;
            var latpro;

            lonpro = (valorMaximoLongitudParcial + valorMinimoLongitudParcial)/2;
            latpro = (valorMaximoLatitudParcial + valorMinimoLatitudParcial)/2;

            lonpro = lonpro*Math.pow(10,14);
            latpro = latpro*Math.pow(10,14);

            lonpro = Math.round(lonpro);
            latpro = Math.round(latpro);

            lonpro = lonpro/Math.pow(10,14);
            latpro = latpro/Math.pow(10,14);

            var punto = new google.maps.LatLng(latpro, lonpro);
            mapa.setCenter(punto);
        }
    }
    else
    {
        //se obtiene los valores de los componentes que estan mas hacia los bordes
        var cmp = new hidcomponente(1,1,1,1);

        if(cmp.hidcomp_numElem(componentes) > 0)
        {
            var valorMaximoLongitudComponente = cmp.hidcomp_lngmayor(componentes);
            var valorMaximoLatitudComponente = cmp.hidcomp_latmayor(componentes);
            var valorMinimoLongitudComponente = cmp.hidcomp_lngmenor(componentes);
            var valorMinimoLatitudComponente = cmp.hidcomp_latmenor(componentes);


            /*  Se debe comprobar que los limites del mapa no dejen fuera los componentes
             */

            if(valorMaximoLongitudParcial < valorMaximoLongitudComponente)
            {
                var dif = (valorMaximoLongitudComponente - valorMaximoLongitudParcial);
                valorMaximoLongitudParcial = valorMaximoLongitudParcial + dif;
                valorMinimoLongitudParcial = valorMinimoLongitudParcial + dif;
            }

            if(valorMinimoLongitudParcial > valorMinimoLongitudComponente)
            {
                var dif = (valorMinimoLongitudParcial - valorMinimoLongitudComponente);
                valorMinimoLongitudParcial = valorMinimoLongitudParcial - dif;
                valorMaximoLongitudParcial = valorMaximoLongitudParcial - dif;
            }

            if(valorMaximoLatitudParcial < valorMinimoLatitudComponente)
            {
                var dif = (valorMinimoLatitudComponente - valorMaximoLatitudParcial);
                valorMaximoLatitudParcial = valorMaximoLatitudParcial + dif;
                valorMinimoLatitudParcial = valorMinimoLatitudParcial + dif;
            }

            if(valorMinimoLatitudParcial > valorMaximoLatitudComponente)
            {
                var dif = (valorMinimoLatitudParcial - valorMaximoLatitudComponente);
                valorMinimoLatitudParcial = valorMinimoLatitudParcial - dif;
                valorMaximoLatitudParcial = valorMaximoLatitudParcial - dif;
            }

            document.getElementById("idcomponenteslat").value = valorMaximoLongitudComponente;
            document.getElementById("idcomponenteslong").value = valorMaximoLatitudComponente;
            document.getElementById("idtiposdecomponente").value = valorMinimoLongitudComponente;
            document.getElementById("ididecomponente").value = valorMinimoLatitudComponente;
        }


        //se debe calcular la nueva posicion del centro del mapa
        var lonpro;
        var latpro;

        lonpro = (valorMaximoLongitudParcial + valorMinimoLongitudParcial)/2;
        latpro = (valorMaximoLatitudParcial + valorMinimoLatitudParcial)/2;

        lonpro = lonpro*Math.pow(10,14);
        latpro = latpro*Math.pow(10,14);

        lonpro = Math.round(lonpro);
        latpro = Math.round(latpro);

        lonpro = lonpro/Math.pow(10,14);
        latpro = latpro/Math.pow(10,14);

        var punto = new google.maps.LatLng(latpro, lonpro);
        mapa.setCenter(punto);
    }
};

function ControlarZoom()
{
    if(mapa.getZoom() >  10)
    {
        mapa.setZoom(10);
    }

    if(mapa.getZoom() <  8)
    {
        mapa.setZoom(8);
    }

    ControlarBordes();
};

function MostrarMarcadores()
{
    /* se debe recorrer el arreglo de marcadores y agregarlos al mapa (grafica)*/
    if (markersArray) {
        for (i in markersArray) {
            markersArray[i].setMap(mapa);
        }
    }
};

function MostrarLineas()
{
    //se recorre el arreglo de lineas y se actualiza las posiciones
    for (i in lineArray)
    {
        CrearPolilinea(i,'#000000');
        ActualizarPathPolilinea(i);
        AgregarEventoLinea(poly[i]);
    }
};

function CrearPolilinea(posicion, color)
{
    var polyOptions = {
        strokeColor: color,
        strokeOpacity: 1.0,
        strokeWeight: 3,
        clickable: true
    }

    if(poly[posicion] == null)
    {
        poly[posicion] = new google.maps.Polyline(polyOptions);
        poly[posicion].setMap(mapa);
        poly[posicion].posicion = posicion;
    }
}

function ActualizarPathPolilinea(posicion)
{
    var pathpolilinea = poly[posicion].getPath();

    //se debe de agregar los puntos de cada elemento del arreglo de lineas en una nueva polilinea
    //del mapa
    var linea = lineArray[posicion];

    var latitudlongitud1 = new google.maps.LatLng(linea[0], linea[1]);
    var latitudlongitud2 = new google.maps.LatLng(linea[2], linea[3]);

    poly[posicion].idpoly = linea[5];

    //quitamos los elementos y lo llenamos con los nuevos datos (laitudes y longitudes)
    pathpolilinea.clear();
    pathpolilinea.push(latitudlongitud1);
    pathpolilinea.push(latitudlongitud2);

    //asignamos esa nueva posicion al path de la lineas
    poly[i].setPath(pathpolilinea);
}

function AgregarEventoLinea(polylinea)
{
    //se debe agregar los eventos a cada polilinea
    google.maps.event.addListener(polylinea, 'dblclick', function() {
        EliminarLinea(polylinea.posicion, polylinea.idpoly);
    });
};

function EliminarLinea(posicion, idpoly)
{
    //obtenemos el path de la linea a eliminar y eliminamos sus componentes
    var pathpolilinea = poly[posicion].getPath();
    pathpolilinea.pop();
    pathpolilinea.pop();
    if(isNaN(idpoly) == false)
    {
        eliminadosArray.push(idpoly);
    }

};

function imagenMarcador(rutaMarcador, componenteunico)
{
    //asignamos la ruta de la imagen del componente y su indicador de si es un elemento o varios
    document.getElementById("marcador").value = rutaMarcador;
    document.getElementById("marcadorunico").value = componenteunico;

    if(componenteunico == "true")
    {
        document.getElementById("inilinea").value = "";
        document.getElementById("inilinea2").value = "";
    }
};

//extraer los valores de una lista contenida dentro de una entrada
//html (input), cuyos datos estan separados por algun delimitador
function ExtraerLista(nombreLista, delimitador)
{
    var lista = [];
    lista = document.getElementById(nombreLista).value.split(delimitador);
    //alert(lista);
    return lista;
};

//extraer los valores de una entrada html
function ExtraerValor(identificador)
{
    var valor = document.getElementById(identificador).value;
    return valor;
};

function AsignarValor(identificador, valor)
{
    document.getElementById(identificador).value = valor;
}

function AgregarNombre(posicion)
{
    //construimos una ventana para el ingreso del nombre del componente
    var htmlBox = CrearVentanaModal("Nombre de Componente","300px","20px");
    var input = CrearInputText("text","30","30");
    var select = CrearComboSeleccion();
    var br = CrearSaltoDeLinea();
    var editBtn = CrearBoton("Agregar");
    var container = CrearContenedorVentana();

    container.appendChild(htmlBox);
    container.appendChild(input);
    container.appendChild(select);
    container.appendChild(br);
    container.appendChild(editBtn);

    //creamos una ventana de informacion con la ventana creada
    var infowindow = new google.maps.InfoWindow({
        content: container,
        position: posicion
    });

    //asignamos el evento al boton de la ventana para 'click'
    google.maps.event.addDomListener(editBtn, "click", function() {
        input.readOnly = true;
        setTimeout(function () { infowindow.close(); }, 500);
        //CrearContenidoMarcador(posicion, input.value);
        CrearContenidoMarcador(posicion, input.value, select.value);
    });

    //mostramos la ventana en el mapa
    infowindow.open(mapa);
}

function CrearVentanaModal(titulo, ancho, alto)
{
    var htmlBox = document.createElement("div");
    htmlBox.innerHTML = titulo;
    htmlBox.style.width = ancho;
    htmlBox.style.height = alto;
    return htmlBox;
}

function CrearInputText(tipo, tamaño, maximoTamaño)
{
    var input = document.createElement("input");
    input.type = tipo;
    input.size = tamaño;
    input.maxLength = maximoTamaño;
    return input;
}

function CrearSaltoDeLinea()
{
    var br = document.createElement('br');
    return br;
}

function CrearContenedorVentana()
{
    var container = document.createElement("div");
    container.style.position = "relative";
    return container;
}

function CrearBoton(nombre)
{
    var editBtn = document.createElement("button");
    editBtn.style.width = "100px";
    editBtn.style.height = "25px";
    var buttonText = document.createTextNode(nombre);
    editBtn.appendChild(buttonText);
    return editBtn;
}

function CrearComboSeleccion()
{
    var idsTipoPuntoMonitoreo = ExtraerLista("idsTipoPuntoMonitoreo",",");
    var nombresTipoPuntoMonitoreo = ExtraerLista("nomTipoPuntoMonitoreo",",");

    var select = document.createElement('select');

    for (var i = 0; i < idsTipoPuntoMonitoreo.length - 1; i++)
    {
        var option = CrearOpcionesComboSeleccion(idsTipoPuntoMonitoreo[i], nombresTipoPuntoMonitoreo[i]);
        select.appendChild(option);
    }

    return select;
}

function CrearOpcionesComboSeleccion(id, nombre)
{
    var option = document.createElement('option');
    var t = document.createTextNode(nombre);
    option.appendChild(t);
    option.setAttribute("value",parseInt(id));

    return option;
}

function CrearContenidoMarcador(posicion, nombreComponente, tipoPuntoMonitoreo)
{
    //se crea una marcador y los agregamos a la lista de marcadores par aluego mostrarlo
    var hidmarcador1 = new hidmarcador(posicion,nombreComponente,'../../../../public/images/Componentes/', tipoPuntoMonitoreo);
    hidmarcador1.AgregarMarcador();
    MostrarMarcadores();
}